using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;
using UnityEngine;


/*
 * 
 *Socket客户端通信类
 * 
 * lm
 */
public class SocketHelper
{

    private static SocketHelper socketHelper = new SocketHelper();
    private Socket socket;
    private object readLock = new object();
    private object writeLock = new object();
    public Queue<byte[]> readQueue = new Queue<byte[]>();
    public Queue<byte[]> writeQueue = new Queue<byte[]>();
    private Thread sendThread;
    private Thread recvThread;
    //饿汉模式
    public static SocketHelper GetInstance()
    {
        return socketHelper;
    }

    private SocketHelper()
    {

        //采用TCP方式连接
        socket = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

    }
    public void ConnectToServer(string ip, int port)
    {

        //服务器IP地址
        IPAddress address = IPAddress.Parse(ip);

        //服务器端口
        IPEndPoint endpoint = new IPEndPoint(address, port);

        //异步连接,连接成功调用connectCallback方法
        IAsyncResult result = socket.BeginConnect(endpoint, new AsyncCallback(ConnectCallback), socket);

        //这里做一个超时的监测，当连接超过5秒还没成功表示超时
        bool success = result.AsyncWaitHandle.WaitOne(Config.CONNECT_TIMEOUT, true);
        if (!success)
        {
            //超时
            Closed();
            Debug.Log("connect Time Out");
        }
        else
        {
            //与socket建立连接成功，开启线程接受服务端数据。
            recvThread = new Thread(new ThreadStart(ReceiveSocket));
            recvThread.IsBackground = true;
            recvThread.Start();
            sendThread = new Thread(new ThreadStart(SendSocket));
            sendThread.IsBackground = true;
            sendThread.Start();
        }
    }

    private void ConnectCallback(IAsyncResult asyncConnect)
    {
        Debug.Log("connect success");
    }

    private void SendSocket()
    {
        while (true)
        {

            if (!socket.Connected)
            {
                //与服务器断开连接跳出循环
                Debug.Log("Failed to clientSocket server.");
                socket.Close();
                break;
            }
            try
            {
                lock (writeLock)
                {
                    if (writeQueue.Count > 0)
                    {
                        byte[] sendMsg = writeQueue.Dequeue();
                        if (sendMsg != null)
                        {
                            SendMessageInner(sendMsg);
                        }
                    }
                }
            }
            catch (Exception e)
            {
                Debug.Log("Failed to clientSocket error." + e);
                socket.Close();
                break;
            }
            Thread.Sleep(10);
        }
    }

    public byte[] FetchPack()
    {
        lock (readLock)
        {
            if (readQueue.Count > 0)
                return readQueue.Dequeue();
            return null;
        }
    }

    private void ReceiveSocket()
    {
        //在这个线程中接受服务器返回的数据
        while (true)
        {

            if (!socket.Connected)
            {
                //与服务器断开连接跳出循环
                Debug.Log("Failed to clientSocket server.");
                socket.Close();
                break;
            }
            try
            {
                //接受数据保存至bytes当中
                byte[] bytes = new byte[Config.RECV_BUFFER_SIZE];
                //Receive方法中会一直等待服务端回发消息
                //如果没有回发会一直在这里等着。
                socket.Receive(bytes, 0, 4, SocketFlags.None);
                int len = System.Net.IPAddress.NetworkToHostOrder(BitConverter.ToInt32(bytes, 0));
                if (len <= 0)
                {
                    socket.Close();
                    break;
                }
                int i = socket.Receive(bytes, 0, len - 4, SocketFlags.None);
                if (i <= 0)
                {
                    socket.Close();
                    break;
                }
                else {
                    lock (readLock)
                    {
                        readQueue.Enqueue(bytes);
                    }

                }
                //Debug.Log(System.Text.Encoding.Default.GetString(bytes));
            }
            catch (Exception e)
            {
                Debug.Log("Failed to clientSocket error." + e);
                socket.Close();
                break;
            }
        }
    }



    //关闭Socket
    public void Closed()
    {
        if (sendThread != null)
            sendThread.Abort();
        if (recvThread != null)
            recvThread.Abort();
        if (socket != null && socket.Connected)
        {
            socket.Shutdown(SocketShutdown.Both);
            socket.Close();
        }
        readQueue.Clear();
        writeQueue.Clear();
        socket = null;

    }

    public void SendMsg(byte[] msg)
    {
        lock (writeLock)
        {
            writeQueue.Enqueue(msg);
        }
    }

    private void SendMessageInner(byte[] msg)
    {

        if (!socket.Connected)
        {
            socket.Close();
            return;
        }
        try
        {
            IAsyncResult asyncSend = socket.BeginSend(msg, 0, msg.Length, SocketFlags.None, new AsyncCallback(SendCallback), socket);
            bool success = asyncSend.AsyncWaitHandle.WaitOne(Config.WRITE_TIMEOUT, true);
            if (!success)
            {
                //超时
                Closed();
                Debug.Log("write Time Out");
            }
        }
        catch
        {
            Debug.Log("send message error");
        }
    }



    private void SendCallback(IAsyncResult asyncConnect)
    {
        int bytesSent = socket.EndSend(asyncConnect);
        Debug.Log("sendCallback: sent" + bytesSent);

    }


}
